home *** CD-ROM | disk | FTP | other *** search
/ BBS Toolkit / BBS Toolkit.iso / doors_2 / tetris13.zip / TETRIS.C next >
Text File  |  1992-01-05  |  43KB  |  1,475 lines

  1. /* ---------------------------------------------------------------------- */
  2. /* TETRIS                                                                 */
  3. /*                                                                        */
  4. /* Compiler   MicroSoft C 5.0                                             */
  5. /*            Quick     C 1.0                                             */
  6. /*                                                                        */
  7. /* (c) 1988   R.A. van Wier                                               */
  8. /*            Nwe Prinsengr. 60 II                                        */
  9. /*            1018 VT  Amsterdam                                          */
  10. /*                                                                        */
  11. /*          This program is a clone of the tetris program          */
  12. /*          by A. Pajitnov & V. Gerasimov.                  */
  13. /*                                                                        */
  14. /*          This software may be used, copied and altered          */
  15. /*          in terms that the source will always be supplied          */
  16. /*          with the program and that the CopyRight remarks          */
  17. /*          are not removed or altered.                  */
  18. /*                                                                        */
  19. /*          Keep FreeWare free of viruses, add sources          */
  20. /* ---------------------------------------------------------------------- */
  21. /* further changes by Markus Noller 01-91                  */
  22. /*        - added automatic multi-line capability              */
  23. /*        - added selectable Topscore placement with "-m" parameter      */
  24. /*                                      */
  25. /*                    12-91:                  */
  26. /*        -included MAXCOMM.DLL, now COMM.DLL *OR* MAXCOMM.DLL      */
  27. /*         can be used by TETRIS/2 in DOOR mode !              */
  28. /*                                      */
  29. /*                    08-91 :                  */
  30. /*                                                                        */
  31. /*        -removed a smaller bug in semaphore handling, which did      */
  32. /*         arise only in OS/2 1.0 systems, fixed now for ALL systems      */
  33. /*                                                                        */
  34. /* ---------------------------------------------------------------------- */
  35. /* changes by Markus Noller 11-90 :                      */
  36. /*                                      */
  37. /*        - textes and comments altered to english              */
  38. /*                                      */
  39. /*        - interface altered for ANSI compatibility              */
  40. /*                                      */
  41. /*        - program changed to DOOR-Program (for BBS use)          */
  42. /*                                      */
  43. /*        - program use changed to pure OS/2                  */
  44. /*                                      */
  45. /*        - mouse interface removed                      */
  46. /*                                      */
  47. /* compile:    cl -Gs -G2 tetris.c    (for OS/2)              */
  48. /*                                      */
  49. /*------------------------------------------------------------------------*/
  50. /* Aanpassingen door de Wizard of Frobozz : 08-88                         */
  51. /*                                                                        */
  52. /*          - Model teruggebracht tot Small. alleen scherm array hoeft    */
  53. /*            far te zijn. Dit zorgt voor kleinere, en snellere code      */
  54. /*                                                                        */
  55. /*          - OS/2 geimplementeerd. Opmerkingen hierbij:                  */
  56. /*                                                                        */
  57. /*                  * OS/2 versie schrijft ook direct naar scherm. Via    */
  58. /*                    het OS het scherm benaderen is te traag voor de     */
  59. /*                    gewenste snelheid. DUS NIET SWITCHEN !              */
  60. /*                  * Timing problemen maken OS/2 versie sneller dan DOS  */
  61. /*                                                                        */
  62. /*          - Deze source compileren met :                                */
  63. /*                  cl -Ox -DOS2 -G2 -Lp tetris.c    (voor OS/2)          */
  64. /*                                                                        */
  65. /*------------------------------------------------------------------------*/
  66. #define INCL_DOSPROCESS
  67. #define INCL_DOSSEMAPHORES
  68. #define INCL_DOSDATETIME
  69. #define INCL_DOSINFOSEG
  70. #define INCL_DOSMODULEMGR
  71. #include <os2.h>
  72.  
  73. #include <stdio.h>
  74. #include <stdlib.h>
  75. #include <string.h>
  76.  
  77. #define  DOOR
  78.  
  79. #ifdef     DOOR
  80. //#include "comm.h"
  81.  
  82. typedef SHANDLE  HCOMM;
  83. #define COMMAPI  pascal far
  84.  
  85. static     HCOMM      hcomm;
  86. static     BOOL      bDoor = 0;
  87. static     SHORT      state = 0;
  88. static     SHORT      remain = -1;
  89. static     SHORT      start_time;
  90. #endif
  91.  
  92. static long    reaction_time;
  93. static int     start_level;
  94. static int     level;
  95. static char    name[255];
  96. static char    ThreadStack[2000];
  97. static TID     tid;
  98.  
  99. #define KEY_END     0x0045
  100. #define KEY_RIGHT   0x4D00
  101. #define KEY_LEFT    0x4B00
  102. #define KEY_DROP    0x0020
  103. #define KEY_ROTATER 0x4800
  104. #define KEY_ROTATEL 0x5000
  105. #define KEY_RANDOM  0x0052
  106. #define KEY_SOUND   0x0042
  107.  
  108. #define INIT_SHAPE  0
  109. #define DOWN_SHAPE  1
  110. #define RIGHT_SHAPE 2
  111. #define LEFT_SHAPE  3
  112. #define ROT_SHAPEL  4
  113. #define ROT_SHAPER  5
  114.  
  115.  
  116. #define BLANK_SCREEN      0x0700 | ' '
  117.  
  118. #define CHAR_FULL       (unsigned char)219
  119. #define COLOUR_BLACK       0
  120. #define COLOUR_BROWN       6  // 6
  121. #define COLOUR_GREY       7
  122. #define COLOUR_GREEN       10 // 10
  123. #define COLOUR_CYAN       14 // 11
  124. #define COLOUR_RED       9  // 12
  125. #define COLOUR_MAGENTA       13 // 13
  126. #define COLOUR_YELLOW       11 // 14
  127. #define COLOUR_WHITE       15
  128. #define COLOUR_SCORE       75
  129. #define COLOUR_TOPSCORE    30
  130. #define COLOUR_LOGO       31
  131. #define COLOUR_NEXT       16
  132.  
  133. #define COLOUR_BORDER       3
  134.  
  135. #define LOG_SIZE_ROW       20
  136. #define LOG_SIZE_COL       10
  137.  
  138. #define MIN_ROW        2
  139. #define MAX_ROW        (LOG_SIZE_ROW + MIN_ROW)
  140. #define MIN_COL        28
  141. #define MAX_COL        (MIN_COL + (LOG_SIZE_COL * 2))
  142.  
  143. #define NUMBER_SHAPES       7
  144. #define SIZE_OF_SHAPE       3
  145.  
  146. #define SCORE_FILE       "TETRIS.TOP"
  147. #define NUMBER_SCORES       20
  148.  
  149. #define INFINITE       -1L
  150. #define TIMEOUT        10000L /* millisewconds */
  151.  
  152. typedef int           SHAPE[SIZE_OF_SHAPE][SIZE_OF_SHAPE];
  153. static SHAPE           shapes[NUMBER_SHAPES + 1];
  154. static SHAPE           actual_shape;
  155.  
  156. static int           shape_points[NUMBER_SHAPES + 1];
  157. static int           next_shape = -1;
  158. static int           log_screen [LOG_SIZE_ROW][LOG_SIZE_COL];
  159. static int           stat_screen[LOG_SIZE_ROW][LOG_SIZE_COL];
  160. static int           col;
  161. static long           points;
  162. static unsigned        keys;
  163. static int           beep_on = 1;
  164. static int           random_on = 0;
  165.  
  166. static int           old_row = 0;
  167. static int           old_column = 0;
  168. static int           old_colour = 0;
  169.  
  170. /* --- Semaphores --- */
  171.  
  172. #define SEM_NAME       "\\SEM\\TETRIS%d"
  173. #define ERROR_SEM_TIMEOUT  121
  174.  
  175. static long           rsKeyGet = 0;
  176. static long           rsKeyGot = 0;
  177. static HSEM           semTimeOut = 0;
  178.  
  179. static MUXSEMLIST       mslSemList;
  180. static USHORT           usIndexNr;
  181.  
  182. static HTIMER           hTimer;
  183.  
  184. #ifdef DOOR
  185.  
  186. /* --- Comm Functions --- */
  187.  
  188. static PFN           ComHRegister;
  189. static PFN           ComClose;
  190. static PFN           ComPutc;
  191. static PFN           ComRxWait;
  192. static PFN           ComGetc;
  193. static PFN           ComInCount;
  194. static PFN           ComIsOnline;
  195.  
  196. /* ---------------------------------------------------------------------- */
  197. /* ComResolve                                  */
  198. /* Task   : Load COMM.DLL and resolve APIs                  */
  199. /*                                                                        */
  200. /* ---------------------------------------------------------------------- */
  201. void ComResolve()
  202. {
  203.    char    errortext[80];
  204.    HMODULE hmodComm;
  205.  
  206.    if( DosLoadModule(errortext, 79, "MAXCOMM", &hmodComm))
  207.    {
  208.       printf("Missing File: %s\n",errortext);
  209.       if( DosLoadModule(errortext, 79, "COMM", &hmodComm))
  210.       {
  211.       printf("Missing File: %s\n",errortext);
  212.       exit(1);
  213.       }
  214.    }
  215.    DosGetProcAddr(hmodComm, "COMHREGISTER", &ComHRegister);
  216.    DosGetProcAddr(hmodComm, "COMCLOSE",     &ComClose);
  217.    DosGetProcAddr(hmodComm, "COMPUTC",        &ComPutc);
  218.    DosGetProcAddr(hmodComm, "COMRXWAIT",    &ComRxWait);
  219.    DosGetProcAddr(hmodComm, "COMGETC",        &ComGetc);
  220.    DosGetProcAddr(hmodComm, "COMINCOUNT",   &ComInCount);
  221.    DosGetProcAddr(hmodComm, "COMISONLINE",  &ComIsOnline);
  222. }
  223.  
  224. /* ---------------------------------------------------------------------- */
  225. /* ComPuts                                  */
  226. /* Task   : Put String to Port                          */
  227. /*                                                                        */
  228. /* ---------------------------------------------------------------------- */
  229. LONG ComPuts(HCOMM hc, CHAR *s)
  230. {
  231. while (*s != '\0')
  232.    {
  233.    (*ComPutc)(hc, *s);
  234.    s++;
  235.    }
  236. }
  237.  
  238. /* ---------------------------------------------------------------------- */
  239. /* ComREADs                                  */
  240. /* Task   : Get String from Port                      */
  241. /*                                                                        */
  242. /* ---------------------------------------------------------------------- */
  243. SHORT ComReads(HCOMM hc, CHAR *buffer, SHORT length)
  244. {
  245. SHORT    index;
  246.  
  247.     index = 0;
  248.     do
  249.     {
  250.     do
  251.     {
  252.         while ((*ComRxWait)(hc, TIMEOUT) == ERROR_SEM_TIMEOUT)
  253.         {
  254.         if (!(*ComIsOnline)(hc))
  255.             DosExit(1,2);
  256.         }
  257.         buffer[index] = (*ComGetc)(hc) ;
  258.     }
  259.     while ((buffer[index] < ' ' || index >= length)
  260.            && buffer[index] != '\x0d' && buffer[index] != '\x08') ;
  261.     if (buffer[index] == '\x08')
  262.     {
  263.         if (index > 0)
  264.         {
  265.         ComPuts(hc,"\x08 \x08");
  266.         index-- ;
  267.         }
  268.     }
  269.     else
  270.     {
  271.         (*ComPutc)(hc, buffer[index]) ;
  272.         index++ ;
  273.     }
  274.     }
  275.     while (buffer[index-1] != '\x0d') ;
  276.     buffer[index-1] = '\n';
  277.     buffer[index]   = '\0';
  278.     (*ComPutc)(hc,'\x0a');
  279.  
  280. return index;
  281. }
  282.  
  283. /* ---------------------------------------------------------------------- */
  284. /* Comm_KEYS                                  */
  285. /* Task   : Check if keys are pressed and read them if so          */
  286. /* ---------------------------------------------------------------------- */
  287. void APIENTRY comm_keys()
  288. {
  289.    while (1)
  290.    {
  291.       while ((*ComRxWait)(hcomm, TIMEOUT) == ERROR_SEM_TIMEOUT)
  292.       {
  293.      if (!(*ComIsOnline)(hcomm))
  294.         DosExit(1,2);
  295.       }
  296.       keys = (*ComGetc)(hcomm);
  297.  
  298.       switch (keys)
  299.       {
  300.      case '8':          keys = KEY_ROTATER; break;
  301.      case '6':          keys = KEY_RIGHT;   break;
  302.      case '4':          keys = KEY_LEFT;      break;
  303.      case '2':          keys = KEY_ROTATEL; break;
  304.      case '\033':
  305.         while ((*ComRxWait)(hcomm, TIMEOUT) == ERROR_SEM_TIMEOUT)
  306.         {
  307.            if (!(*ComIsOnline)(hcomm))
  308.           DosExit(1,2);
  309.         }
  310.         keys = (*ComGetc)(hcomm);
  311.         if (keys == '[')
  312.         {
  313.            while ((*ComRxWait)(hcomm, TIMEOUT) == ERROR_SEM_TIMEOUT)
  314.            {
  315.           if (!(*ComIsOnline)(hcomm))
  316.              DosExit(1,2);
  317.            }
  318.            keys = (*ComGetc)(hcomm);
  319.            switch (keys)
  320.            {
  321.           case 'A':   keys = KEY_ROTATER; break;
  322.           case 'B':   keys = KEY_ROTATEL; break;
  323.           case 'C':   keys = KEY_RIGHT;   break;
  324.           case 'D':   keys = KEY_LEFT;      break;
  325.           default :   keys = '\0';
  326.            }
  327.         }
  328.         else
  329.                   keys = '\0';
  330.         break;
  331.      default:          keys = toupper(keys) ;
  332.       }
  333.  
  334.       if (remain == 0)          keys = KEY_END;
  335.  
  336.       if (keys != '\0')
  337.       {
  338.      DosSemSet   ( (HSEM) &rsKeyGet);
  339.      DosSemClear ( (HSEM) &rsKeyGot);
  340.      DosSemWait  ( (HSEM) &rsKeyGet, INFINITE);
  341.       }
  342.    }
  343. }
  344.  
  345. #endif
  346.  
  347.  
  348. /* ---------------------------------------------------------------------- */
  349. /* SYSTIME                                                                */
  350. /* Task   : Returns system time in timer ticks                  */
  351. /*                                                                        */
  352. /* ---------------------------------------------------------------------- */
  353. long systime(int res)
  354. {
  355.     static long far *pGlob = (long far *)0;
  356.     if (pGlob == (long far *)0) {
  357.             unsigned selG, selL;
  358.         DosGetInfoSeg((PSEL)&selG, (PSEL)&selL);
  359.             pGlob = (long far *)((long)selG << 16);
  360.     }
  361.     return(pGlob[res]);
  362. }
  363.  
  364. /* ---------------------------------------------------------------------- */
  365. /* READ_KEYS                                  */
  366. /* Task   : Check if keys are pressed and read them if so          */
  367. /* ---------------------------------------------------------------------- */
  368. void APIENTRY read_keys()
  369. {
  370.    while (1)
  371.    {
  372.       keys = getch();
  373.       if ( keys == 0 || keys == 0xE0 )
  374.      keys = ( getch() << 8);
  375.       else
  376.      keys = toupper(keys) ;
  377.       DosSemSet   ( (HSEM) &rsKeyGet);
  378.       DosSemClear ( (HSEM) &rsKeyGot);
  379.       DosSemWait  ( (HSEM) &rsKeyGet, INFINITE);
  380.    }
  381. }
  382.  
  383. /* ---------------------------------------------------------------------- */
  384. /* WAIT_KEYS                                  */
  385. /* Task   : Wait until a Key is pressed                   */
  386. /*                                                                        */
  387. /* ---------------------------------------------------------------------- */
  388. static void wait_keys()
  389. {
  390.       DosSemWait( (HSEM) &rsKeyGot, INFINITE);
  391. }
  392.  
  393. /* ---------------------------------------------------------------------- */
  394. /* CLEAR_KDB_BUFFER                              */
  395. /* Task   : Clear Keyboard buffer                      */
  396. /*                                                                        */
  397. /* ---------------------------------------------------------------------- */
  398. static void clear_kbd_buffer()
  399. {
  400.    if (DosSemWait( (HSEM) &rsKeyGot, 10L) == ERROR_SEM_TIMEOUT)
  401.       return ; /* Nothing in buffer */
  402. #ifdef DOOR
  403.    if (bDoor)
  404.       while ( (*ComInCount)(hcomm) > 0)
  405.      (void) (*ComGetc)(hcomm);
  406.    else
  407. #endif
  408.       while (  kbhit() )
  409.      (void) getch();
  410.    DosSemSet  ( (HSEM) &rsKeyGot );
  411.    DosSemClear( (HSEM) &rsKeyGet );
  412. }
  413.  
  414. /* ---------------------------------------------------------------------- */
  415. /* BEEP                                                                   */
  416. /* Task   : Give a BEEP                           */
  417. /*                                                                        */
  418. /* ---------------------------------------------------------------------- */
  419. static void beep()
  420. {
  421.    if (beep_on)
  422. #ifdef DOOR
  423.       if (bDoor)
  424.      (*ComPutc)(hcomm,'\007');
  425.       else
  426. #endif
  427.      putch('\007');
  428. }
  429.  
  430. /* ---------------------------------------------------------------------- */
  431. /* PUT_CHARACTER                              */
  432. /* Task   : Put a character on screen at a given position with          */
  433. /*        a given colour                          */
  434. /*                                                                        */
  435. /* ---------------------------------------------------------------------- */
  436. static void put_character(int row, int column, int colour,
  437.               unsigned int charac)
  438. {
  439.  
  440.    char scratch[80];
  441.  
  442.    if (colour != old_colour)
  443.    {
  444.       sprintf(scratch, "\033[%01d;%02dm",(colour & 8) >>3, (colour &7)+30 );
  445. #ifdef DOOR
  446.       if (bDoor)
  447.     ComPuts(hcomm, scratch);
  448. #endif
  449.       printf(scratch);
  450.    }
  451.  
  452.    if (row != old_row || column != old_column)
  453.       {
  454.       sprintf(scratch, "\033[%02d;%02dH%c", row + 1, column + 1, charac) ;
  455. #ifdef DOOR
  456.       if (bDoor)
  457.      ComPuts(hcomm, scratch);
  458. #endif
  459.       printf(scratch);
  460.       }
  461.    else
  462.       {
  463. #ifdef DOOR
  464.       if (bDoor)
  465.      (*ComPutc)(hcomm, charac);
  466. #endif
  467.       putchar(charac) ;
  468.       }
  469.  
  470.    old_row    = row ;
  471.    old_column = column + 1 ;
  472.    old_colour = colour ;
  473. }
  474. /* ---------------------------------------------------------------------- */
  475. /* PUT_STRING                                  */
  476. /* Task   : Place a string on the screen at a given position and in a      */
  477. /*        given colour                          */
  478. /*                                                                        */
  479. /* ---------------------------------------------------------------------- */
  480. static void put_string(int row, int column, int colour,
  481.                unsigned char *string)
  482. {
  483.  
  484.    char scratch[150];
  485.  
  486.    if (colour != old_colour)
  487.    {
  488.       sprintf(scratch, "\033[%01d;%02dm",(colour & 8) >>3, (colour &7)+30 );
  489. #ifdef DOOR
  490.       if (bDoor)
  491.     ComPuts(hcomm, scratch);
  492. #endif
  493.     printf(scratch);
  494.    }
  495.  
  496.    if (row != old_row || column != old_column)
  497.       {
  498.       sprintf(scratch, "\033[%02d;%02dH%s", row + 1, column + 1, string) ;
  499. #ifdef DOOR
  500.       if (bDoor)
  501.      ComPuts(hcomm, scratch);
  502. #endif
  503.       printf(scratch);
  504.       }
  505.    else
  506.       {
  507. #ifdef DOOR
  508.       if (bDoor)
  509.      ComPuts(hcomm, string);
  510. #endif
  511.       printf(string) ;
  512.       }
  513.  
  514.    old_row    = row ;
  515.    old_column = column + strlen(string) ;
  516.    old_colour = colour ;
  517. }
  518.  
  519. /* ---------------------------------------------------------------------- */
  520. /* CLS                                                                    */
  521. /* Task   : Clear Screen                          */
  522. /*                                                                        */
  523. /* ---------------------------------------------------------------------- */
  524. static void cls()
  525. {
  526. #ifdef DOOR
  527.    if (bDoor)
  528.      ComPuts(hcomm,"\033[2J");
  529. #endif
  530.    printf("\033[2J");
  531. }
  532.  
  533. /* ---------------------------------------------------------------------- */
  534. /* INIT_SCREEN                                  */
  535. /* Task   : Fill the screen with the layout                  */
  536. /*                                                                        */
  537. /* ---------------------------------------------------------------------- */
  538.  
  539. static void init_screen()
  540. {
  541.    register int   i;
  542.    char       scratch[100];
  543.    long       now;
  544.  
  545.    /* Start random funktion */
  546.  
  547.    now = systime(1);
  548.    srand(now % 32113);
  549.  
  550.    /* Put the border on the screen */
  551.  
  552.    cls();
  553.  
  554.    for ( i =  MIN_ROW      ; i <= MAX_ROW; i++ )
  555.    {
  556.        put_character(i, MIN_COL-1, COLOUR_BORDER, CHAR_FULL);
  557.        put_character(i, MAX_COL,   COLOUR_BORDER, CHAR_FULL);
  558.    }
  559.    for ( i = (MIN_COL -1) ; i <= MAX_COL; i++ )
  560.        put_character(MAX_ROW, i, COLOUR_BORDER, CHAR_FULL);
  561.  
  562. #ifdef DOOR
  563.    if (remain > 0)
  564.       sprintf(scratch," T E T R I S / 2   %-20.20s  remaining: mmm (c) 1991, Markus Noller ",name);
  565.    else
  566. #endif
  567.       sprintf(scratch," T E T R I S / 2    hh:mm:ss   %-20.20s     (c) 1991, Markus Noller ",name);
  568.    put_string(0, 0, COLOUR_LOGO, scratch);
  569.    put_string(2, 3, COLOUR_MAGENTA, "Version 1.3");
  570.  
  571.    put_string(24, 0, COLOUR_LOGO, " keys : cursor LEFT RIGHT, UP/DOWN=rotate, E=exit, R=random, B=beep, SPACE=drop");
  572.  
  573. }
  574.  
  575. /* ---------------------------------------------------------------------- */
  576. /* SHOW_TIME                                  */
  577. /* Task   : Show the time on the screen                   */
  578. /*                                                                        */
  579. /* ---------------------------------------------------------------------- */
  580.  
  581. static void show_time()
  582. {
  583.    char        scratch[20];
  584. #ifdef DOOR
  585.    int           time;
  586.  
  587.    if (remain > 0)
  588.    {
  589.       time = systime(0);
  590.       if (time - start_time >= 60)
  591.       {
  592.      remain--;
  593.      start_time += 60;
  594.       }
  595.       sprintf(scratch,"%3d", remain);
  596.       put_string(0, 52, COLOUR_LOGO, scratch);
  597.    }
  598.    else
  599. #endif
  600.    {
  601.       _strtime(scratch);
  602.       put_string(0, 20, COLOUR_LOGO, scratch);
  603.    }
  604. }
  605.  
  606. /* ---------------------------------------------------------------------- */
  607. /* SHOW_STATUS                                                            */
  608. /* Task   : Shows the status of RANDOM                      */
  609. /* ---------------------------------------------------------------------- */
  610.  
  611. static void show_status()
  612. {
  613.    put_string(16, 66, COLOUR_NEXT | COLOUR_WHITE,"            ");
  614.    if ( random_on )
  615.       put_string(17, 66, COLOUR_NEXT | COLOUR_WHITE,"   RANDOM   ");
  616.    else
  617.       put_string(17, 66, COLOUR_NEXT | COLOUR_WHITE,"            ");
  618.  
  619.    put_string(18, 66, COLOUR_NEXT | COLOUR_WHITE,"            ");
  620. }
  621.  
  622. /* ---------------------------------------------------------------------- */
  623. /* SHOW_SCORE                                                             */
  624. /* Task   : Shows the score and the level on the screen           */
  625. /*        and displays the next SHAPE                   */
  626. /* ---------------------------------------------------------------------- */
  627.  
  628. static void show_score()
  629. {
  630.    char      scratch[80];
  631.    register int  i,j,x;
  632.  
  633.    put_string(10, 0, COLOUR_SCORE, "             ");
  634.    sprintf(scratch," level  %1d / %1d ",start_level,level);
  635.    put_string(11,0,COLOUR_SCORE,scratch);
  636.    put_string(12,0,COLOUR_SCORE,"             ");
  637.    sprintf(scratch," Score %5ld ",points);
  638.    put_string(13,0,COLOUR_SCORE,scratch);
  639.    put_string(14,0,COLOUR_SCORE,"             ");
  640.    put_string(15,0,COLOUR_SCORE,"             ");
  641.  
  642.    put_string(10,66,COLOUR_NEXT | COLOUR_GREY,"  following  ");
  643.    put_string(11,66,COLOUR_NEXT         ,"            ");
  644.    put_string(12,66,COLOUR_NEXT         ,"            ");
  645.    put_string(13,66,COLOUR_NEXT         ,"            ");
  646.    put_string(14,66,COLOUR_NEXT         ,"            ");
  647.    put_string(15,66,COLOUR_NEXT         ,"            ");
  648.  
  649.    /* Plaats de volgende SHAPE op het screen */
  650.  
  651.    for ( i = 0; i < 3 ; i++)
  652.    {
  653.       for ( j = 0; j < 3; j++ )
  654.       {
  655.       x = shapes[next_shape][i][j];
  656.       if ( x != COLOUR_BLACK )
  657.           {
  658.          put_character(12+i,69+j+j    ,COLOUR_NEXT | x,CHAR_FULL);
  659.          put_character(12+i,69+j+j+1,COLOUR_NEXT | x,CHAR_FULL);
  660.           }
  661.       }
  662.    }
  663.    show_status();
  664. }
  665. /* ---------------------------------------------------------------------- */
  666. /* SHOW_TOPSCORE                                                          */
  667. /* Task   : Shows the Top score (only one per player)              */
  668. /*                                                                        */
  669. /* ---------------------------------------------------------------------- */
  670.  
  671. static void show_topscore(char *pszScore_File)
  672. {
  673.    register int   i,j;
  674.    char       scratch[80];
  675.    long       scratch_score;
  676.    long       scratch_average;
  677.    long       scratch_played;
  678.  
  679.    static struct
  680.       {
  681.         int      number;
  682.         long     score   [NUMBER_SCORES];
  683.         long     average [NUMBER_SCORES];
  684.         long     played  [NUMBER_SCORES];
  685.         char     name    [NUMBER_SCORES]  [22];
  686.       }
  687.       score_record;
  688.  
  689.    FILE       *score_file;
  690.  
  691.    /* Read in the scores */
  692.  
  693.    score_file = fopen(pszScore_File,"rb");
  694.    if ( score_file == NULL )
  695.       score_record.number = 0;
  696.    else
  697.    {
  698.       if ( fread(&score_record,sizeof(score_record),1,score_file) < 1)
  699.      score_record.number = 0;
  700.       fclose(score_file);
  701.    }
  702.  
  703.    /* Look if the current player is already in the score list  */
  704.  
  705.    name[21] = '\0';
  706.    strupr(name);
  707.    j  = 99;
  708.    for ( i = 0; i < score_record.number; i++ )
  709.    {
  710.        if ( strcmp(name,score_record.name[i]) == 0 )
  711.           j = i;
  712.    }
  713.    if ( j < 99 )
  714.    {
  715.        /* Calculate the scores (top/average) of the current player */
  716.        /* over the last ten games                   */
  717.  
  718.        if ( points > score_record.score[j] )
  719.       score_record.score[j] = points;
  720.        score_record.average[j] =
  721.              ( ( score_record.average[j] * score_record.played[j] )
  722.                  + points ) / ( score_record.played[j] + 1);
  723.        score_record.played[j] = score_record.played[j] + 1;
  724.        if (score_record.played[j] > 10) score_record.played[j] = 10;
  725.    }
  726.    else
  727.    {
  728.       if ( score_record.number < NUMBER_SCORES )
  729.       {
  730.      /* Add player to the list */
  731.  
  732.      score_record.score  [score_record.number] = points;
  733.      score_record.average[score_record.number] = points;
  734.      score_record.played [score_record.number] = 1;
  735.      strcpy(score_record.name[score_record.number],name);
  736.      j = score_record.number;
  737.      score_record.number++;
  738.       }
  739.       else
  740.       {
  741.      if ( points > score_record.score[NUMBER_SCORES - 1] )
  742.          {
  743.         /* Replace last player with current */
  744.  
  745.         score_record.score    [NUMBER_SCORES - 1] = points;
  746.         score_record.average[NUMBER_SCORES - 1] = points;
  747.         score_record.played [NUMBER_SCORES - 1] = 1;
  748.         strcpy(score_record.name[NUMBER_SCORES - 1],name);
  749.         j = NUMBER_SCORES - 1;
  750.          }
  751.       }
  752.    }
  753.  
  754.    if ( j < 99 )
  755.    {
  756.       /* raise current player if he improved */
  757.  
  758.       while (   ( j > 0 )
  759.             &&  ( score_record.score[j] > score_record.score[j-1] ) )
  760.       {
  761.      /* Raise player by one */
  762.  
  763.      strcpy (scratch,score_record.name[j-1]);
  764.      scratch_score     = score_record.score    [j-1];
  765.      scratch_average = score_record.average [j-1];
  766.      scratch_played  = score_record.played    [j-1];
  767.  
  768.      strcpy(score_record.name[j-1],score_record.name[j]);
  769.      score_record.score   [j-1] = score_record.score   [j];
  770.      score_record.average [j-1] = score_record.average [j];
  771.      score_record.played  [j-1] = score_record.played  [j];
  772.  
  773.      strcpy(score_record.name[j],scratch);
  774.      score_record.score   [j] = scratch_score;
  775.      score_record.average [j] = scratch_average;
  776.      score_record.played  [j] = scratch_played;
  777.  
  778.          j--;
  779.       }
  780.    }
  781.  
  782.    /* Write scores to disk */
  783.  
  784.    score_file = fopen(pszScore_File,"wb");
  785.    if ( score_file != NULL )
  786.    {
  787.       fwrite(&score_record,sizeof(score_record),1,score_file);
  788.       fclose(score_file);
  789.    }
  790.  
  791.    /* Show score on screen */
  792.  
  793.    for (i = 0; i < LOG_SIZE_ROW; i++)
  794.    {
  795.        if ( i < score_record.number )
  796.       sprintf(scratch," Top %5ld, average %5ld points %-18.18s ",
  797.                   score_record.score[i],
  798.           score_record.average[i],score_record.name[i]);
  799.        else
  800.       strcpy(scratch,"                                                   ");
  801.        put_string(MIN_ROW+i,MIN_COL,COLOUR_TOPSCORE,scratch);
  802.    }
  803. }
  804.  
  805. /* ---------------------------------------------------------------------- */
  806. /* LOG_DISPLAY                                                            */
  807. /* Task   : Show alteren patterns in logical screen (20x10) on physical   */
  808. /*                                                                        */
  809. /* ---------------------------------------------------------------------- */
  810.  
  811. static void log_display()
  812. {
  813.    register int     i, j;
  814.  
  815.    for ( i = 0; i < LOG_SIZE_ROW; i++ )
  816.    {
  817.        for ( j = 0; j < LOG_SIZE_COL; j++ )
  818.        {
  819.      /* 1 logical point is 2 blocks on screen */
  820.  
  821.      if (log_screen[i][j] != stat_screen[i][j])
  822.      {
  823.        put_character(MIN_ROW+i,MIN_COL+(j*2),log_screen[i][j],CHAR_FULL);
  824.        put_character(MIN_ROW+i,MIN_COL+1+(j*2),log_screen[i][j],CHAR_FULL);
  825.        stat_screen[i][j] = log_screen[i][j];
  826.      }
  827.        }
  828.    }
  829. }
  830.  
  831. /* ---------------------------------------------------------------------- */
  832. /* LOG_CLS                                                                */
  833. /* Task   : Clear logical screen                      */
  834. /*                                                                        */
  835. /* ---------------------------------------------------------------------- */
  836. static void log_cls()
  837. {
  838.    register int     i, j;
  839.  
  840.    for ( i = 0 ; i < LOG_SIZE_ROW; i++)
  841.    {
  842.        for ( j = 0; j < LOG_SIZE_COL; j++)
  843.        {
  844.        log_screen [i][j] = COLOUR_BLACK;
  845.        stat_screen[i][j] = COLOUR_WHITE;
  846.        }
  847.    }
  848.    log_display();
  849. }
  850.  
  851. /* ---------------------------------------------------------------------- */
  852. /* RM_FULL_ROW                                  */
  853. /* Task   : Remove a full row from the logical screen              */
  854. /*                                                                        */
  855. /* ---------------------------------------------------------------------- */
  856. static void rm_full_row()
  857. {
  858.    register int    i, j;
  859.    int           x, action;
  860.  
  861.    for ( i = LOG_SIZE_ROW - 1 ; i > 0; i--)
  862.    {
  863.        /* Look if there is a hole in this row */
  864.  
  865.        action = 1;
  866.        for ( j = 0; action && (j < LOG_SIZE_COL); j++)
  867.        {
  868.        if (log_screen[i][j] == COLOUR_BLACK) action = 0;
  869.        }
  870.  
  871.        if ( action )
  872.        {
  873.       /* Copy the rows above the full row one row down */
  874.  
  875.           for ( x = i ; x > 0; x--)
  876.           {
  877.          for ( j = 0; j < LOG_SIZE_COL; j++)
  878.              {
  879.          log_screen[x][j] = log_screen[x-1][j];
  880.              }
  881.           }
  882.       /* Make the highest Row all black */
  883.  
  884.       for ( j = 0; j < LOG_SIZE_COL; j++)
  885.           {
  886.           log_screen[0][j] = COLOUR_BLACK;
  887.           }
  888.       /* Beep and look for this row again */
  889.  
  890.           beep();
  891.           log_display();
  892.           i++;
  893.        }
  894.    }
  895. }
  896.  
  897. /* ---------------------------------------------------------------------- */
  898. /* PUT_SHAPE                                  */
  899. /* Task   : Put the current shape onto the logical screen and manipulate  */
  900. /*                                                                        */
  901. /* ---------------------------------------------------------------------- */
  902. static int put_shape(int action)
  903.                          /* 0 = initial put       */
  904.                          /* 1 = move down          */
  905.                          /* 2 = right          */
  906.                          /* 3 = left          */
  907.                          /* 4 = rotate left       */
  908.                          /* 5 = rotate right      */
  909. {
  910.    register int   i, j;
  911.  
  912.    static   int   reg, col;
  913.    int          scratch, collision;
  914.  
  915.    collision = 1;
  916.  
  917.    if ( action != INIT_SHAPE )
  918.    {
  919.       /* clean the shape from it's old position */
  920.  
  921.       for ( i = 0; i < 3; i++ )
  922.       {
  923.          for ( j = 0; j < 3; j++ )
  924.          {
  925.         if ( actual_shape[i][j] != COLOUR_BLACK )
  926.            log_screen[reg+i][col+j]   = COLOUR_BLACK;
  927.          }
  928.       }
  929.    }
  930.  
  931.    switch(action)
  932.    {
  933.       case INIT_SHAPE :  /* initial placing */
  934.                reg = 0;
  935.            col = LOG_SIZE_COL / 2;
  936.                break;
  937.       case DOWN_SHAPE :  /* move down */
  938.                reg++;
  939.                break;
  940.       case RIGHT_SHAPE : /* move to the right */
  941.            col++;
  942.                break;
  943.       case LEFT_SHAPE :  /* move to the left */
  944.            col--;
  945.                break;
  946.       case ROT_SHAPEL :   /* rotate shape left */
  947.            scratch          = actual_shape[0][0];
  948.            actual_shape[0][0] = actual_shape[0][2];
  949.            actual_shape[0][2] = actual_shape[2][2];
  950.            actual_shape[2][2] = actual_shape[2][0];
  951.            actual_shape[2][0] = scratch;
  952.  
  953.            scratch          = actual_shape[1][0];
  954.            actual_shape[1][0] = actual_shape[0][1];
  955.            actual_shape[0][1] = actual_shape[1][2];
  956.            actual_shape[1][2] = actual_shape[2][1];
  957.            actual_shape[2][1] = scratch;
  958.                break;
  959.       case ROT_SHAPER :   /* rotate shape right */
  960.            scratch          = actual_shape[0][0];
  961.            actual_shape[0][0] = actual_shape[2][0];
  962.            actual_shape[2][0] = actual_shape[2][2];
  963.            actual_shape[2][2] = actual_shape[0][2];
  964.            actual_shape[0][2] = scratch;
  965.  
  966.            scratch          = actual_shape[0][1];
  967.            actual_shape[0][1] = actual_shape[1][0];
  968.            actual_shape[1][0] = actual_shape[2][1];
  969.            actual_shape[2][1] = actual_shape[1][2];
  970.            actual_shape[1][2] = scratch;
  971.                break;
  972.    }
  973.  
  974.    /* Look for a collision on the new place */
  975.  
  976.    for ( i = 0; i < 3; i++ )
  977.    {
  978.       for ( j = 0; j < 3; j++ )
  979.       {
  980.      if ( actual_shape[i][j] != COLOUR_BLACK )
  981.          {
  982.         if    ( log_screen[reg+i][col+j] != COLOUR_BLACK )
  983.         collision = 0;
  984.         if ( ( reg+i ) >= LOG_SIZE_ROW ) collision = 0;
  985.         if ( ( reg+i ) < 0 ) collision = 0;
  986.         if ( ( col+j ) >= LOG_SIZE_COL ) collision = 0;
  987.         if ( ( col+j ) < 0 ) collision = 0;
  988.          }
  989.       }
  990.    }
  991.  
  992.    if ( collision == 0 )
  993.    {
  994.       /* Restore old status */
  995.       switch(action)
  996.       {
  997.      case DOWN_SHAPE :
  998.                   reg--;
  999.                   break;
  1000.      case RIGHT_SHAPE :
  1001.           col--;
  1002.                   break;
  1003.      case LEFT_SHAPE :
  1004.           col++;
  1005.                   break;
  1006.      case ROT_SHAPEL :
  1007.           scratch         = actual_shape[0][0];
  1008.           actual_shape[0][0] = actual_shape[2][0];
  1009.           actual_shape[2][0] = actual_shape[2][2];
  1010.           actual_shape[2][2] = actual_shape[0][2];
  1011.           actual_shape[0][2] = scratch;
  1012.  
  1013.           scratch         = actual_shape[1][0];
  1014.           actual_shape[1][0] = actual_shape[2][1];
  1015.           actual_shape[2][1] = actual_shape[1][2];
  1016.           actual_shape[1][2] = actual_shape[0][1];
  1017.           actual_shape[0][1] = scratch;
  1018.                   break;
  1019.      case ROT_SHAPER :
  1020.           scratch         = actual_shape[0][0];
  1021.           actual_shape[0][0] = actual_shape[0][2];
  1022.           actual_shape[0][2] = actual_shape[2][2];
  1023.           actual_shape[2][2] = actual_shape[2][0];
  1024.           actual_shape[2][0] = scratch;
  1025.  
  1026.           scratch         = actual_shape[0][1];
  1027.           actual_shape[0][1] = actual_shape[1][2];
  1028.           actual_shape[1][2] = actual_shape[2][1];
  1029.           actual_shape[2][1] = actual_shape[1][0];
  1030.           actual_shape[1][0] = scratch;
  1031.                   break;
  1032.       }
  1033.    }
  1034.  
  1035.    /* Put the shape on it's new position */
  1036.  
  1037.    for ( i = 0; i < 3; i++ )
  1038.    {
  1039.       for ( j = 0; j < 3; j++ )
  1040.       {
  1041.      if ( actual_shape[i][j] != COLOUR_BLACK )
  1042.         log_screen[reg+i][col+j]   = actual_shape[i][j];
  1043.       }
  1044.    }
  1045.  
  1046.    if ( collision )
  1047.       log_display();
  1048.  
  1049.    return(collision);
  1050. }
  1051.  
  1052. /* ---------------------------------------------------------------------- */
  1053. /* INIT_SHAPES                                  */
  1054. /* Task   : Draw the forms to the form table                  */
  1055. /*                                                                        */
  1056. /* ---------------------------------------------------------------------- */
  1057. static void init_shapes()
  1058. {
  1059.    register int   i, j;
  1060.    int          colour;
  1061.  
  1062.    shape_points[0] = 10;
  1063.    colour       = COLOUR_BROWN;
  1064.    shapes[0][0][0] = COLOUR_BLACK;     /*   ..#      */
  1065.    shapes[0][0][1] = COLOUR_BLACK;     /*   .##      */
  1066.    shapes[0][0][2] = colour;           /*   .#.      */
  1067.  
  1068.    shapes[0][1][0] = COLOUR_BLACK;
  1069.    shapes[0][1][1] = colour;
  1070.    shapes[0][1][2] = colour;
  1071.  
  1072.    shapes[0][2][0] = COLOUR_BLACK;
  1073.    shapes[0][2][1] = colour;
  1074.    shapes[0][2][2] = COLOUR_BLACK;
  1075.  
  1076.    shape_points[1] = 10;
  1077.    colour       = COLOUR_CYAN;
  1078.    shapes[1][0][0] = colour ;           /*   #..      */
  1079.    shapes[1][0][1] = COLOUR_BLACK;     /*   ##.      */
  1080.    shapes[1][0][2] = COLOUR_BLACK;     /*   .#.      */
  1081.  
  1082.    shapes[1][1][0] = colour ;
  1083.    shapes[1][1][1] = colour ;
  1084.    shapes[1][1][2] = COLOUR_BLACK;
  1085.  
  1086.    shapes[1][2][0] = COLOUR_BLACK;
  1087.    shapes[1][2][1] = colour ;
  1088.    shapes[1][2][2] = COLOUR_BLACK;
  1089.  
  1090.    shape_points[2] = 1;
  1091.    colour       = COLOUR_RED;
  1092.    shapes[2][0][0] = COLOUR_BLACK;     /*   ...      */
  1093.    shapes[2][0][1] = COLOUR_BLACK;     /*   ###      */
  1094.    shapes[2][0][2] = COLOUR_BLACK;     /*   ...      */
  1095.  
  1096.    shapes[2][1][0] = colour ;
  1097.    shapes[2][1][1] = colour ;
  1098.    shapes[2][1][2] = colour ;
  1099.  
  1100.    shapes[2][2][0] = COLOUR_BLACK;
  1101.    shapes[2][2][1] = COLOUR_BLACK;
  1102.    shapes[2][2][2] = COLOUR_BLACK;
  1103.  
  1104.    shape_points[3] = 7;
  1105.    colour       = COLOUR_MAGENTA;
  1106.    shapes[3][0][0] = COLOUR_BLACK;     /*   ...      */
  1107.    shapes[3][0][1] = COLOUR_BLACK;     /*   ###      */
  1108.    shapes[3][0][2] = COLOUR_BLACK;     /*   ..#      */
  1109.  
  1110.    shapes[3][1][0] = colour ;
  1111.    shapes[3][1][1] = colour ;
  1112.    shapes[3][1][2] = colour ;
  1113.  
  1114.    shapes[3][2][0] = COLOUR_BLACK;
  1115.    shapes[3][2][1] = COLOUR_BLACK;
  1116.    shapes[3][2][2] = colour ;
  1117.  
  1118.    shape_points[4] = 7;
  1119.    colour       = COLOUR_YELLOW;
  1120.    shapes[4][0][0] = COLOUR_BLACK;     /*   ...      */
  1121.    shapes[4][0][1] = COLOUR_BLACK;     /*   ###      */
  1122.    shapes[4][0][2] = COLOUR_BLACK;     /*   #..      */
  1123.  
  1124.    shapes[4][1][0] = colour ;
  1125.    shapes[4][1][1] = colour ;
  1126.    shapes[4][1][2] = colour ;
  1127.  
  1128.    shapes[4][2][0] = colour ;
  1129.    shapes[4][2][1] = COLOUR_BLACK;
  1130.    shapes[4][2][2] = COLOUR_BLACK;
  1131.  
  1132.    shape_points[5] = 4;
  1133.    colour       = COLOUR_GREY;
  1134.    shapes[5][0][0] = COLOUR_BLACK;     /*   ...      */
  1135.    shapes[5][0][1] = COLOUR_BLACK;     /*   ##.      */
  1136.    shapes[5][0][2] = COLOUR_BLACK;     /*   ##.      */
  1137.  
  1138.    shapes[5][1][0] = colour ;
  1139.    shapes[5][1][1] = colour ;
  1140.    shapes[5][1][2] = COLOUR_BLACK;
  1141.  
  1142.    shapes[5][2][0] = colour ;
  1143.    shapes[5][2][1] = colour ;
  1144.    shapes[5][2][2] = COLOUR_BLACK;
  1145.  
  1146.    shape_points[6] = 3;
  1147.    colour       = COLOUR_GREEN;
  1148.    shapes[6][0][0] = COLOUR_BLACK;     /*   ...      */
  1149.    shapes[6][0][1] = COLOUR_BLACK;     /*   .#.      */
  1150.    shapes[6][0][2] = COLOUR_BLACK;     /*   ###      */
  1151.  
  1152.    shapes[6][1][0] = COLOUR_BLACK;
  1153.    shapes[6][1][1] = colour ;
  1154.    shapes[6][1][2] = COLOUR_BLACK;
  1155.  
  1156.    shapes[6][2][0] = colour ;
  1157.    shapes[6][2][1] = colour ;
  1158.    shapes[6][2][2] = colour;
  1159.  
  1160. }
  1161.  
  1162. /* ---------------------------------------------------------------------- */
  1163. /* RANDOM_SHAPE                               */
  1164. /* Task   : Select a Random Shape and store points of it          */
  1165. /*                                                                        */
  1166. /* ---------------------------------------------------------------------- */
  1167.  
  1168. static void random_shape()
  1169. {
  1170.    register int   i, j;
  1171.    static   int   tel = 0;
  1172.    static   long  vpoints = 0;
  1173.  
  1174.    if (  ( vpoints > points )
  1175.       || ( next_shape < 0 ) )
  1176.    {
  1177.       vpoints = 0;
  1178.       tel = 0;
  1179.       next_shape = rand() % NUMBER_SHAPES;
  1180.    }
  1181.  
  1182.    /* Place the chosen shape in actual_shape */
  1183.  
  1184.    for ( i = 0; i < 3 ; i++)
  1185.    {
  1186.       for ( j = 0; j < 3; j++ )
  1187.       {
  1188.       actual_shape[i][j] = shapes[next_shape][i][j];
  1189.       }
  1190.    }
  1191.    points = points + shape_points[next_shape] + start_level;
  1192.  
  1193.    tel++;
  1194.  
  1195.    if (  ( ( tel % 25 ) == 0 )
  1196.       && ( level < 9 ) )
  1197.    {
  1198.       level++;
  1199.       reaction_time = (10 - level) * 60;
  1200.       DosSemClear ( semTimeOut) ;
  1201.       DosTimerStop (hTimer) ;
  1202.       DosSemSet ( semTimeOut) ;
  1203.       DosTimerStart (reaction_time, semTimeOut, &hTimer) ;
  1204.       beep();
  1205.    }
  1206.  
  1207.    vpoints = points;
  1208.    if (  ( random_on )
  1209.       && ( rand() % 2 ) )
  1210.    {
  1211.       /* Generate a random shape */
  1212.  
  1213.       next_shape = NUMBER_SHAPES;
  1214.       for ( i = 0; i < 3 ; i++)
  1215.       {
  1216.          for ( j = 0; j < 3; j++ )
  1217.          {
  1218.              if ( rand() % 2 )
  1219.         shapes[next_shape][i][j] = COLOUR_WHITE;
  1220.              else
  1221.         shapes[next_shape][i][j] = COLOUR_BLACK;
  1222.          }
  1223.       }
  1224.       shapes[next_shape][1][1] = COLOUR_WHITE;
  1225.       shape_points[next_shape] = 50;
  1226.    }
  1227.    else
  1228.       next_shape = rand() % NUMBER_SHAPES;
  1229.    show_score();
  1230. }
  1231.  
  1232. /* ------------------------------------------------------------------------ */
  1233. /*                                                                          */
  1234. /*             M A I N   P R O G R A M                    */
  1235. /*                                                                          */
  1236. /* ------------------------------------------------------------------------ */
  1237.  
  1238. void main(argc, argv)
  1239. int  argc;
  1240. char *argv[];
  1241. {
  1242.    register   int      i;
  1243.    register   int      drop;
  1244.    char           scratch[80];
  1245.    char           pszSemName[15];
  1246.    char           pszScoreFile[128];
  1247.  
  1248.    level  = 99;
  1249.    name[0] = '\0';
  1250.    strcpy(pszScoreFile,SCORE_FILE);
  1251.  
  1252. #ifdef DOOR
  1253.  
  1254.    for (i=1; i<argc; i++)
  1255.    {
  1256.       if ((argv[i][0] == '-') || (argv[i][0] == '/'))
  1257.       {
  1258.      switch (argv[i][1])
  1259.      {
  1260.         case 'p':
  1261.            ComResolve();
  1262.            (* ComHRegister) (atoi(&argv[i][2]), (HCOMM far *) &hcomm, 0, 0);
  1263.            bDoor = TRUE;
  1264.            break;
  1265.  
  1266.         case 'n':
  1267.            strcpy(name,&argv[i][2]);
  1268.            while ((i+1 < argc) && (argv[i+1][0] != '-'))
  1269.            {
  1270.           i++;
  1271.           if (name[0] != '\0')
  1272.              strcat(name," ");
  1273.           strcat(name, argv[i]);
  1274.            }
  1275.            break;
  1276.  
  1277.         case 'l':
  1278.            level = atoi(&argv[i][2]);
  1279.            break;
  1280.  
  1281.         case 'r':
  1282.            remain = atoi(&argv[i][2]);
  1283.            start_time = systime(0);
  1284.            break;
  1285.  
  1286.         case 'm':
  1287.            strcpy(pszScoreFile,(&argv[i][2]));
  1288.            break;
  1289.      }
  1290.       }
  1291.    }
  1292. #endif
  1293.  
  1294.    /* Ask for players name and skill level */
  1295.  
  1296.    while ( name[0] == '\0' )
  1297.    {
  1298. #ifdef DOOR
  1299.       if (bDoor)
  1300.       {
  1301.      ComPuts(hcomm, "\nPlease give your name: ");
  1302.      ComReads(hcomm, name, 22);
  1303.       }
  1304.       else
  1305. #endif
  1306.       {
  1307.      printf("\nPlease give your name: ");
  1308.      gets(name);
  1309.       }
  1310.    }
  1311.    i = strlen(name) - 1;
  1312.    while ( (name[i] == ' ' || name[i] == '\n') && (i > 0) )  i--;
  1313.    i++;
  1314.    name[i] = '\0';
  1315.  
  1316.    while (  ( level < 0 )
  1317.      || ( level > 9 ) )
  1318.    {
  1319. #ifdef DOOR
  1320.       if (bDoor)
  1321.       {
  1322.      sprintf(scratch, "\nWhat skill level, %s (0..9)? ",name) ;
  1323.      ComPuts(hcomm, scratch) ;
  1324.      ComReads(hcomm, scratch, 2) ;
  1325.      level = atoi(scratch) ;
  1326.       }
  1327.       else
  1328. #endif
  1329.       {
  1330.      printf("\nWhat skill level, %s (0..9)? ",name);
  1331.      scanf("%d",&level);
  1332.       }
  1333.    }
  1334.  
  1335.    start_level = level;
  1336.    points = 0;
  1337.  
  1338.    /* Initialize the screen */
  1339.  
  1340.    init_screen();
  1341.    log_cls();
  1342.    init_shapes();
  1343.  
  1344.    put_string(MIN_ROW,MIN_COL+3,COLOUR_WHITE,"Press a key");
  1345.  
  1346. #ifdef DOOR
  1347.    if (bDoor)
  1348.       DosCreateThread( (PFNTHREAD) comm_keys, &tid, &ThreadStack[1999]);
  1349.    else
  1350. #endif
  1351.       DosCreateThread( (PFNTHREAD) read_keys, &tid, &ThreadStack[1999]);
  1352.    clear_kbd_buffer();
  1353.    wait_keys();
  1354.  
  1355.    put_string(MIN_ROW,MIN_COL+3,COLOUR_WHITE,"           ");
  1356.  
  1357.    i=0;
  1358.    do
  1359.    {
  1360.       if (i>99)
  1361.      exit (100);
  1362.       sprintf(pszSemName,SEM_NAME, i);
  1363.       i++;
  1364.    }
  1365.    while (DosCreateSem(CSEM_PUBLIC, &semTimeOut, pszSemName) != 0);
  1366.  
  1367.    mslSemList.cmxs = 2L;
  1368.    mslSemList.amxs[0].zero = 0L;
  1369.    mslSemList.amxs[1].zero = 0L;
  1370.    mslSemList.amxs[0].hsem = (HSEM) &rsKeyGot;
  1371.    mslSemList.amxs[1].hsem = semTimeOut;
  1372.  
  1373.    reaction_time = (10 - level) * 60;
  1374.    DosSemSet ( (HSEM) semTimeOut) ;
  1375.    DosTimerStart (reaction_time, semTimeOut, &hTimer);
  1376.  
  1377.    random_shape();
  1378.  
  1379.    while (( keys != KEY_END )
  1380.      && ( put_shape(0) ) )         /* set new shape on screen */
  1381.    {
  1382.       drop = 0;
  1383.       keys = 0;
  1384.       DosSemSet  ( (HSEM) &rsKeyGot );
  1385.       DosSemClear( (HSEM) &rsKeyGet );
  1386.  
  1387.       while (( keys != KEY_END )
  1388.         && ( put_shape(1) ) )
  1389.       {
  1390.       /* Process the keys pressed and move the shape down one row */
  1391.  
  1392.       show_time();
  1393.  
  1394.       while (( !drop )
  1395.      && ( keys != KEY_END ))
  1396.      {
  1397.  
  1398.      DosMuxSemWait(&usIndexNr, &mslSemList, INFINITE);
  1399.  
  1400.      /* Process the keys */
  1401.  
  1402.      if (usIndexNr == 0)
  1403.         {
  1404.         switch(keys)
  1405.            {
  1406.            case KEY_RIGHT     :
  1407.                    put_shape(RIGHT_SHAPE);
  1408.                    break;
  1409.            case KEY_LEFT     :
  1410.                    put_shape(LEFT_SHAPE);
  1411.                    break;
  1412.            case KEY_DROP     :
  1413.                    i = 0;
  1414.                    while( put_shape(DOWN_SHAPE)) i++;
  1415.                    points = points + start_level +
  1416.                       ((i / LOG_SIZE_ROW) * start_level);
  1417.                    drop = 1;
  1418.                    break;
  1419.            case KEY_SOUND     :
  1420.                    beep_on = !beep_on;
  1421.                    break;
  1422.            case KEY_RANDOM     :
  1423.                    random_on = !random_on;
  1424.                    show_status();
  1425.                    break;
  1426.            case KEY_ROTATEL  :
  1427.                    put_shape(ROT_SHAPEL);
  1428.                    break;
  1429.            case KEY_ROTATER  :
  1430.                    put_shape(ROT_SHAPER);
  1431.                    break;
  1432.            }
  1433.         DosSemSet  ( (HSEM) &rsKeyGot );
  1434.         DosSemClear( (HSEM) &rsKeyGet );
  1435.         }
  1436.      else
  1437.         {
  1438.         DosSemSet ( semTimeOut) ;
  1439.         if (!put_shape(DOWN_SHAPE))
  1440.            break;
  1441.         }
  1442.      }
  1443.  
  1444.       }
  1445.       /* Remove full rows, clear kbd buffer and get a new shape */
  1446.  
  1447.       rm_full_row();
  1448.       clear_kbd_buffer();
  1449.       random_shape();
  1450.    }
  1451.  
  1452.    if ( keys != KEY_END )
  1453.    {
  1454.       /* Show the score until a key is pressed */
  1455.  
  1456.       show_topscore(pszScoreFile);
  1457.       DosSleep(100L);
  1458.       clear_kbd_buffer();
  1459.       wait_keys();
  1460.    }
  1461.    put_string(0,0,COLOUR_GREY," ");
  1462.    cls();
  1463.  
  1464. #ifdef DOOR
  1465.    if (bDoor)
  1466.    {
  1467.       if (remain == 0)
  1468.      ComPuts(hcomm, "\nTimelimit exceeded, Program ended. Sorry\n");
  1469.       (* ComClose) (hcomm);
  1470.    }
  1471. #endif
  1472.    exit(0);
  1473. }
  1474. 
  1475.